package utils

/*
	工具函数集
*/

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"github.com/segmentio/ksuid"
	"math"
	"math/big"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"shorturl/configs"
	"sort"
	"strconv"
	"strings"
	"time"
)

// StrToInt 字符串转int
func StrToInt(str string) int {
	i, _ := strconv.Atoi(str)
	return i
}

// StrToInt64 字符串转int64
func StrToInt64(str string) int64 {
	i, _ := strconv.ParseInt(str, 10, 64)
	return i
}

// StrToFloat64 字符串转Float64
func StrToFloat64(str string) float64 {
	i, _ := strconv.ParseFloat(str, 64)
	return i
}

// StrToFloat32 字符串转Float32
func StrToFloat32(str string) float32 {
	i, _ := strconv.ParseFloat(str, 32)
	return float32(i)
}

// IntToStr 数字转字符串
func IntToStr(i int) string {
	return strconv.Itoa(i)
}

// Md5 md5加密
func Md5(str string) string {
	m := md5.New()
	m.Write([]byte(str))
	return hex.EncodeToString(m.Sum(nil))
}

// Sha256 计算给定字符串的 SHA-256 哈希值
func Sha256(data string) string {
	// 计算数据的 SHA-256 哈希值
	hash := sha256.Sum256([]byte(data))

	// 将哈希值转换为十六进制字符串并返回
	return hex.EncodeToString(hash[:])
}

// RsaEncrypt RSA加密
func RsaEncrypt(origData string) string {
	return origData
}

// RsaDecrypt RSA解密
func RsaDecrypt(origData string) ([]byte, error) {
	// 构建私钥文件路径
	privateKeyPath := filepath.Join(GetRootPath(), "cert", "secret", "private.pem")

	// 读取私钥文件内容
	privateKeyPEM, err := os.ReadFile(privateKeyPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read private key file: %w", err)
	}

	// 解码PEM格式的私钥
	block, _ := pem.Decode(privateKeyPEM)
	if block == nil {
		return nil, fmt.Errorf("failed to decode PEM block containing private key")
	}

	// 解析私钥
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse private key: %w", err)
	}

	base64Decode, err := base64.StdEncoding.DecodeString(origData)

	// 使用私钥对原始数据进行解密
	decryptedData, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, base64Decode)
	if err != nil {
		return nil, fmt.Errorf("failed to decrypt data: %w", err)
	}

	return decryptedData, nil
}

// GenerateSignature 生成签名（设备注册时校验 -旧）
func GenerateSignature(timestamp int64) string {
	data := fmt.Sprintf("%d%s", timestamp, "2vWkay8MvNWfFxI0iHZfVloNVi5")
	hash := sha256.New()
	hash.Write([]byte(data))
	signature := hex.EncodeToString(hash.Sum(nil))
	return signature
}

// VerifySignature 验证签名（设备注册时校验 新）
func VerifySignature(timestamp int64, receivedSig string) bool {
	// 时间戳有效性检查（±5分钟）
	if time.Now().UnixMilli()-timestamp > 300000 || timestamp-time.Now().UnixMilli() > 300000 {
		return false
	}

	// 生成HMAC
	mac := hmac.New(sha256.New, []byte("2vWkay8MvNWfFxI0iHZfVloNVi5"))
	mac.Write([]byte(strconv.FormatInt(timestamp, 10))) // 与Python的str(timestamp)一致
	expectedSig := mac.Sum(nil)

	// 安全比较签名
	receivedBytes, _ := hex.DecodeString(receivedSig)
	return hmac.Equal(receivedBytes, expectedSig)
}

// GenerateHashId 生成短HashID
func GenerateHashId() string {
	k := ksuid.New() // 创建一个新的KSUID对象
	shortId := k.String()
	return shortId
}

// GeneratePlatformId 生成平台ID
func GeneratePlatformId() string {
	k := ksuid.New()           // 创建一个新的KSUID对象
	shortId := k.String()[0:6] // 将KSUID转换为字符串形式的短HashID
	return shortId
}

// GenerateSaltId 加盐
func GenerateSaltId() string {
	k := ksuid.New()            // 创建一个新的KSUID对象
	shortId := k.String()[6:12] // 将KSUID转换为字符串形式的短HashID
	return shortId
}

// GenerateInviteCode 邀请码
func GenerateInviteCode() string {
	k := ksuid.New()                   // 创建一个新的KSUID对象
	shortId := k.String()[12:18]       // 将KSUID转换为字符串形式的短HashID
	shortId = strings.ToUpper(shortId) // 转为大写
	return shortId
}

// GenerateToken 生成token
func GenerateToken(customer string) string {
	// 读取配置文件中的秘钥
	config, _ := configs.ReadConfig(GetRootPath() + "/config.json")
	// 加入盐
	salt := config.App.Secret
	return Sha256(customer + salt)
}

// GenerateVerCode 生成随机四位数验证码
func GenerateVerCode() int {
	// 生成一个介于1000和9999之间的随机数
	code, _ := rand.Int(rand.Reader, big.NewInt(9000))
	return int(code.Int64()) + 1000
}

// IsPhone 验证手机号
func IsPhone(phone string) bool {
	// 验证手机号格式
	match, _ := regexp.MatchString(`^1[3-9]\d{9}$`, phone)
	return match
}

// IsEmail 验证邮箱
func IsEmail(email string) bool {
	// 验证邮箱格式
	match, _ := regexp.MatchString(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`, email)
	return match
}

// IsPassword 验证密码 8-16位字母数字特殊字符组合
func IsPassword(password string) bool {
	// 验证密码格式
	match, _ := regexp.MatchString(`^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,16}$`, password)
	return match
}

// GetDate 获取当前日期
func GetDate() string {
	return time.Now().Format("2006-01-02")
}

// GetDateTime 获取当前日期时间
func GetDateTime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

// DateToString 获取日期字符串
func DateToString(date time.Time) string {
	return date.Format("2006-01-02")
}

// GetDistance 获取两个坐标点的距离 单位：km
func GetDistance(lat1, lng1, lat2, lng2 float64) float64 {
	radius := 6378.137 // 地球半径
	rad := math.Pi / 180.0

	lat1 = lat1 * rad
	lng1 = lng1 * rad
	lat2 = lat2 * rad
	lng2 = lng2 * rad

	s := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(lng2-lng1))

	return s * radius
}

// InArray 判断字符串是否在数组中
func InArray(target string, strArray []string) bool {
	sort.Strings(strArray)
	index := sort.SearchStrings(strArray, target)
	if index < len(strArray) && strArray[index] == target {
		return true
	}
	return false
}

// GetFutureDateTime 获取未来日期
func GetFutureDateTime(days int) string {
	// 获取当前时间
	now := time.Now()

	// 创建一个 30 天的时间间隔
	Days := time.Duration(days) * 24 * time.Hour

	// 在当前时间基础上增加指定天数
	futureDate := now.Add(Days)

	return futureDate.Format("2006-01-02 15:04:05")
}

// StrToTime 字符串转time.Time类型
func StrToTime(str string) time.Time {
	t, _ := time.ParseInLocation("2006-01-02 15:04:05", str, time.Local)
	return t
}

// GetStartOfDay 获取当天的开始时间
func GetStartOfDay(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}

// GetEndOfDay 获取当天的结束时间
func GetEndOfDay(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
}

// GetStartOfWeek 获取本周的开始时间
func GetStartOfWeek(t time.Time) time.Time {
	weekday := t.Weekday()
	if weekday == time.Sunday {
		return GetStartOfDay(t.AddDate(0, 0, -6))
	}
	return GetStartOfDay(t.AddDate(0, 0, -int(weekday)+1))
}

// GetEndOfWeek 获取本周的结束时间
func GetEndOfWeek(t time.Time) time.Time {
	weekday := t.Weekday()
	if weekday == time.Sunday {
		return GetEndOfDay(t)
	}
	return GetEndOfDay(t.AddDate(0, 0, 7-int(weekday)))
}

// GetStartOfMonth 获取本月的开始时间
func GetStartOfMonth(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
}

// GetEndOfMonth 获取本月的结束时间
func GetEndOfMonth(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month()+1, 0, 23, 59, 59, 999999999, t.Location())
}

// GetDeviceType 根据User-Agent获取设备类型
func GetDeviceType(userAgent string) string {
	// 示例实现：根据User-Agent判断设备类型
	if strings.Contains(strings.ToLower(userAgent), "mobile") {
		return "Mobile"
	} else if strings.Contains(strings.ToLower(userAgent), "tablet") {
		return "Tablet"
	} else {
		return "PC"
	}
}

// GetOs 根据User-Agent获取操作系统信息
func GetOs(userAgent string) string {
	// 示例实现：根据User-Agent判断操作系统
	if strings.Contains(strings.ToLower(userAgent), "windows") {
		return "Windows"
	} else if strings.Contains(strings.ToLower(userAgent), "macintosh") {
		return "Mac OS"
	} else if strings.Contains(strings.ToLower(userAgent), "linux") {
		return "Linux"
	} else {
		return "Unknown"
	}
}

// GetBrowser 根据User-Agent获取浏览器信息
func GetBrowser(userAgent string) string {
	// 示例实现：根据User-Agent判断浏览器
	if strings.Contains(strings.ToLower(userAgent), "chrome") {
		return "Chrome"
	} else if strings.Contains(strings.ToLower(userAgent), "firefox") {
		return "Firefox"
	} else if strings.Contains(strings.ToLower(userAgent), "safari") {
		return "Safari"
	} else if strings.Contains(strings.ToLower(userAgent), "edge") {
		return "Edge"
	} else {
		return "Unknown"
	}
}

// ParseUrl 解析URL并返回其主机名
func ParseUrl(urlStr string) (*url.URL, error) {
	return url.Parse(urlStr)
}
